added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / jscript / engine / strictequality.cs
blob58512ce83d2dbcd502e4fa2bb45dd803e1a0476a
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 //
14 // ==--==
16 namespace Microsoft.JScript {
18 using Microsoft.JScript.Vsa;
19 using System;
20 using System.Reflection;
21 using System.Reflection.Emit;
23 public class StrictEquality : BinaryOp{
25 internal StrictEquality(Context context, AST operand1, AST operand2, JSToken operatorTok)
26 : base(context, operand1, operand2, operatorTok) {
29 internal override Object Evaluate(){
30 bool result = JScriptStrictEquals(this.operand1.Evaluate(), this.operand2.Evaluate(), VsaEngine.executeForJSEE);
31 if (this.operatorTok == JSToken.StrictEqual)
32 return result;
33 else
34 return !result;
37 public static bool JScriptStrictEquals(Object v1, Object v2){
38 return StrictEquality.JScriptStrictEquals(v1, v2, false);
41 internal static bool JScriptStrictEquals(Object v1, Object v2, bool checkForDebuggerObjects){
42 IConvertible ic1 = Convert.GetIConvertible(v1);
43 IConvertible ic2 = Convert.GetIConvertible(v2);
44 TypeCode t1 = Convert.GetTypeCode(v1, ic1);
45 TypeCode t2 = Convert.GetTypeCode(v2, ic2);
46 return StrictEquality.JScriptStrictEquals(v1, v2, ic1, ic2, t1, t2, checkForDebuggerObjects);
49 internal static bool JScriptStrictEquals(Object v1, Object v2, IConvertible ic1, IConvertible ic2, TypeCode t1, TypeCode t2, bool checkForDebuggerObjects){
50 switch (t1){
51 case TypeCode.Empty: return t2 == TypeCode.Empty;
52 case TypeCode.Object:
53 if (v1 == v2) return true;
54 if (v1 is Missing || v1 is System.Reflection.Missing) v1 = null;
55 if (v1 == v2) return true;
56 if (v2 is Missing || v2 is System.Reflection.Missing) v2 = null;
57 return v1 == v2;
58 case TypeCode.DBNull: return t2 == TypeCode.DBNull;
59 case TypeCode.Boolean: return t2 == TypeCode.Boolean && ic1.ToBoolean(null) == ic2.ToBoolean(null);
61 case TypeCode.Char:
62 Char ch = ic1.ToChar(null);
63 switch(t2){
64 case TypeCode.Char: return ch == ic2.ToChar(null);
65 case TypeCode.SByte:
66 case TypeCode.Byte:
67 case TypeCode.Int16:
68 case TypeCode.UInt16:
69 case TypeCode.Int32:
70 case TypeCode.UInt32:
71 case TypeCode.Int64: return ch == ic2.ToInt64(null);
72 case TypeCode.UInt64: return ch == ic2.ToUInt64(null);
73 case TypeCode.Single:
74 case TypeCode.Double: return ch == ic2.ToDouble(null);
75 case TypeCode.Decimal: return ((Decimal)(int)ch) == ic2.ToDecimal(null);
76 case TypeCode.String:
77 String str = ic2.ToString(null);
78 return str.Length == 1 && ch == str[0];
80 return false;
82 case TypeCode.SByte:
83 SByte sb1 = ic1.ToSByte(null);
84 switch (t2){
85 case TypeCode.Char: return sb1 == ic2.ToChar(null);
86 case TypeCode.SByte:
87 case TypeCode.Byte:
88 case TypeCode.Int16:
89 case TypeCode.UInt16:
90 case TypeCode.Int32:
91 case TypeCode.UInt32:
92 case TypeCode.Int64: return sb1 == ic2.ToInt64(null);
93 case TypeCode.UInt64: return sb1 >= 0 && ((UInt64)sb1) == ic2.ToUInt64(null);
94 case TypeCode.Single: return sb1 == ic2.ToSingle(null);
95 case TypeCode.Double: return sb1 == ic2.ToDouble(null);
96 case TypeCode.Decimal: return ((Decimal)sb1) == ic2.ToDecimal(null);
98 return false;
100 case TypeCode.Byte:
101 Byte b1 = ic1.ToByte(null);
102 switch (t2){
103 case TypeCode.Char: return b1 == ic2.ToChar(null);
104 case TypeCode.SByte:
105 case TypeCode.Byte:
106 case TypeCode.Int16:
107 case TypeCode.UInt16:
108 case TypeCode.Int32:
109 case TypeCode.UInt32:
110 case TypeCode.Int64: return b1 == ic2.ToInt64(null);
111 case TypeCode.UInt64: return b1 == ic2.ToUInt64(null);
112 case TypeCode.Single: return b1 == ic2.ToSingle(null);
113 case TypeCode.Double: return b1 == ic2.ToDouble(null);
114 case TypeCode.Decimal: return ((Decimal)b1) == ic2.ToDecimal(null);
116 return false;
118 case TypeCode.Int16:
119 Int16 s1 = ic1.ToInt16(null);
120 switch (t2){
121 case TypeCode.Char: return s1 == ic2.ToChar(null);
122 case TypeCode.SByte:
123 case TypeCode.Byte:
124 case TypeCode.Int16:
125 case TypeCode.UInt16:
126 case TypeCode.Int32:
127 case TypeCode.UInt32:
128 case TypeCode.Int64: return s1 == ic2.ToInt64(null);
129 case TypeCode.UInt64: return s1 >= 0 && ((UInt64)s1) == ic2.ToUInt64(null);
130 case TypeCode.Single: return s1 == ic2.ToSingle(null);
131 case TypeCode.Double: return s1 == ic2.ToDouble(null);
132 case TypeCode.Decimal: return ((Decimal)s1) == ic2.ToDecimal(null);
134 return false;
136 case TypeCode.UInt16:
137 UInt16 us1 = ic1.ToUInt16(null);
138 switch (t2){
139 case TypeCode.Char: return us1 == ic2.ToChar(null);
140 case TypeCode.SByte:
141 case TypeCode.Byte:
142 case TypeCode.Int16:
143 case TypeCode.UInt16:
144 case TypeCode.Int32:
145 case TypeCode.UInt32:
146 case TypeCode.Int64: return us1 == ic2.ToInt64(null);
147 case TypeCode.UInt64: return us1 == ic2.ToUInt64(null);
148 case TypeCode.Single: return us1 == ic2.ToSingle(null);
149 case TypeCode.Double: return us1 == ic2.ToDouble(null);
150 case TypeCode.Decimal: return ((Decimal)us1) == ic2.ToDecimal(null);
152 return false;
154 case TypeCode.Int32:
155 Int32 i1 = ic1.ToInt32(null);
156 switch (t2){
157 case TypeCode.Char: return i1 == ic2.ToChar(null);
158 case TypeCode.SByte:
159 case TypeCode.Byte:
160 case TypeCode.Int16:
161 case TypeCode.UInt16:
162 case TypeCode.Int32:
163 case TypeCode.UInt32:
164 case TypeCode.Int64: return i1 == ic2.ToInt64(null);
165 case TypeCode.UInt64: return i1 >= 0 && ((UInt64)i1) == ic2.ToUInt64(null);
166 case TypeCode.Single: return i1 == ic2.ToSingle(null);
167 case TypeCode.Double: return i1 == ic2.ToDouble(null);
168 case TypeCode.Decimal: return ((Decimal)i1) == ic2.ToDecimal(null);
170 return false;
172 case TypeCode.UInt32:
173 UInt32 ui1 = ic1.ToUInt32(null);
174 switch (t2){
175 case TypeCode.Char: return ui1 == ic2.ToChar(null);
176 case TypeCode.SByte:
177 case TypeCode.Byte:
178 case TypeCode.Int16:
179 case TypeCode.UInt16:
180 case TypeCode.Int32:
181 case TypeCode.UInt32:
182 case TypeCode.Int64: return ui1 == ic2.ToInt64(null);
183 case TypeCode.UInt64: return ui1 == ic2.ToUInt64(null);
184 case TypeCode.Single: return ui1 == ic2.ToSingle(null);
185 case TypeCode.Double: return ui1 == ic2.ToDouble(null);
186 case TypeCode.Decimal: return ((Decimal)ui1) == ic2.ToDecimal(null);
188 return false;
190 case TypeCode.Int64:
191 Int64 l1 = ic1.ToInt64(null);
192 switch (t2){
193 case TypeCode.Char: return l1 == ic2.ToChar(null);
194 case TypeCode.SByte:
195 case TypeCode.Byte:
196 case TypeCode.Int16:
197 case TypeCode.UInt16:
198 case TypeCode.Int32:
199 case TypeCode.UInt32:
200 case TypeCode.Int64: return l1 == ic2.ToInt64(null);
201 case TypeCode.UInt64: return l1 >= 0 && ((UInt64)l1) == ic2.ToUInt64(null);
202 case TypeCode.Single: return l1 == ic2.ToSingle(null);
203 case TypeCode.Double: return l1 == ic2.ToDouble(null);
204 case TypeCode.Decimal: return ((Decimal)l1) == ic2.ToDecimal(null);
206 return false;
208 case TypeCode.UInt64:
209 UInt64 ul1 = ic1.ToUInt64(null);
210 switch (t2){
211 case TypeCode.Char: return ul1 == ic2.ToChar(null);
212 case TypeCode.SByte:
213 case TypeCode.Byte:
214 case TypeCode.Int16:
215 case TypeCode.UInt16:
216 case TypeCode.Int32:
217 case TypeCode.UInt32:
218 case TypeCode.Int64:
219 l1 = ic2.ToInt64(null);
220 return l1 >= 0 && ul1 == (UInt64)l1;
221 case TypeCode.UInt64: return ul1 == ic2.ToUInt64(null);
222 case TypeCode.Single: return ul1 == ic2.ToSingle(null);
223 case TypeCode.Double: return ul1 == ic2.ToDouble(null);
224 case TypeCode.Decimal: return ((Decimal)ul1) == ic2.ToDecimal(null);
226 return false;
228 case TypeCode.Single:
229 Single f1 = ic1.ToSingle(null);
230 switch (t2){
231 case TypeCode.Char: return f1 == ic2.ToChar(null);
232 case TypeCode.SByte:
233 case TypeCode.Byte:
234 case TypeCode.Int16:
235 case TypeCode.UInt16:
236 case TypeCode.Int32:
237 case TypeCode.UInt32:
238 case TypeCode.Int64: return f1 == ic2.ToInt64(null);
239 case TypeCode.UInt64: return f1 == ic2.ToUInt64(null);
240 case TypeCode.Single: return f1 == ic2.ToSingle(null);
241 case TypeCode.Double: return f1 == ic2.ToSingle(null);
242 case TypeCode.Decimal: return ((Decimal)f1) == ic2.ToDecimal(null);
244 return false;
246 case TypeCode.Double:
247 Double d1 = ic1.ToDouble(null);
248 switch (t2){
249 case TypeCode.Char: return d1 == ic2.ToChar(null);
250 case TypeCode.SByte:
251 case TypeCode.Byte:
252 case TypeCode.Int16:
253 case TypeCode.UInt16:
254 case TypeCode.Int32:
255 case TypeCode.UInt32:
256 case TypeCode.Int64: return d1 == ic2.ToInt64(null);
257 case TypeCode.UInt64: return d1 == ic2.ToUInt64(null);
258 case TypeCode.Single: return ((float)d1) == ic2.ToSingle(null);
259 case TypeCode.Double: return d1 == ic2.ToDouble(null);
260 case TypeCode.Decimal: return ((Decimal)d1) == ic2.ToDecimal(null);
262 return false;
264 case TypeCode.Decimal:
265 Decimal de1 = ic1.ToDecimal(null);
266 switch (t2){
267 case TypeCode.Char: return de1 == (Decimal)(int)ic2.ToChar(null);
268 case TypeCode.SByte:
269 case TypeCode.Byte:
270 case TypeCode.Int16:
271 case TypeCode.UInt16:
272 case TypeCode.Int32:
273 case TypeCode.UInt32:
274 case TypeCode.Int64: return de1 == ic2.ToInt64(null);
275 case TypeCode.UInt64: return de1 == ic2.ToUInt64(null);
276 case TypeCode.Single: return de1 == (Decimal)ic2.ToSingle(null);
277 case TypeCode.Double: return de1 == (Decimal)ic2.ToDouble(null);
278 case TypeCode.Decimal: return de1 == ic2.ToDecimal(null);
280 return false;
282 case TypeCode.DateTime: return t2 == TypeCode.DateTime && ic1.ToDateTime(null) == ic2.ToDateTime(null);
283 case TypeCode.String:
284 if (t2 == TypeCode.Char){
285 String str = ic1.ToString(null);
286 return str.Length == 1 && str[0] == ic2.ToChar(null);
288 return t2 == TypeCode.String && (v1 == v2 || ic1.ToString(null).Equals(ic2.ToString(null)));
290 return false; //should never get here
293 internal override IReflect InferType(JSField inference_target){
294 return Typeob.Boolean;
297 internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm){
298 Type t1 = Convert.ToType(this.operand1.InferType(null));
299 Type t2 = Convert.ToType(this.operand2.InferType(null));
300 if (this.operand1 is ConstantWrapper)
301 if (this.operand1.Evaluate() == null) t1 = Typeob.Empty;
302 if (this.operand2 is ConstantWrapper)
303 if (this.operand2.Evaluate() == null) t2 = Typeob.Empty;
304 if (t1 != t2 && t1.IsPrimitive && t2.IsPrimitive){
305 if (t1 == Typeob.Single)
306 t2 = t1;
307 else if (t2 == Typeob.Single)
308 t1 = t2;
309 else if (Convert.IsPromotableTo(t2, t1))
310 t2 = t1;
311 else if (Convert.IsPromotableTo(t1, t2))
312 t1 = t2;
314 bool nonPrimitive = true;
315 if (t1 == t2 && t1 != Typeob.Object){
316 // Operand types are equal and not Object - need to compare values only. Primitive
317 // values get compared with IL instructions; other values including value types
318 // get compared with Object.Equals. String is special cased for perf.
319 Type t = t1;
320 if (!t1.IsPrimitive)
321 t = Typeob.Object;
322 this.operand1.TranslateToIL(il, t);
323 this.operand2.TranslateToIL(il, t);
324 if (t1 == Typeob.String)
325 il.Emit(OpCodes.Call, CompilerGlobals.stringEqualsMethod);
326 else if (!t1.IsPrimitive)
327 il.Emit(OpCodes.Callvirt, CompilerGlobals.equalsMethod);
328 else
329 nonPrimitive = false;
330 }else if (t1 == Typeob.Empty){
331 this.operand2.TranslateToIL(il, Typeob.Object);
332 branchIfTrue = !branchIfTrue;
333 }else if (t2 == Typeob.Empty){
334 this.operand1.TranslateToIL(il, Typeob.Object);
335 branchIfTrue = !branchIfTrue;
336 }else{
337 this.operand1.TranslateToIL(il, Typeob.Object);
338 this.operand2.TranslateToIL(il, Typeob.Object);
339 il.Emit(OpCodes.Call, CompilerGlobals.jScriptStrictEqualsMethod);
341 if (branchIfTrue){
342 if (this.operatorTok == JSToken.StrictEqual)
343 if (nonPrimitive)
344 il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label);
345 else
346 il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label);
347 else
348 if (nonPrimitive)
349 il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label);
350 else
351 il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label);
352 }else{
353 if (this.operatorTok == JSToken.StrictEqual)
354 if (nonPrimitive)
355 il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label);
356 else
357 il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label);
358 else
359 if (nonPrimitive)
360 il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label);
361 else
362 il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label);
364 return;
367 internal override void TranslateToIL(ILGenerator il, Type rtype){
368 Label true_label = il.DefineLabel();
369 Label done_label = il.DefineLabel();
370 this.TranslateToConditionalBranch(il, true, true_label, true);
371 il.Emit(OpCodes.Ldc_I4_0);
372 il.Emit(OpCodes.Br_S, done_label);
373 il.MarkLabel(true_label);
374 il.Emit(OpCodes.Ldc_I4_1);
375 il.MarkLabel(done_label);
376 Convert.Emit(this, il, Typeob.Boolean, rtype);